/*
    OpenLib
    Copyright (C) 2011  Michael Gukov

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


var jsun = function() {
    if (typeof arguments[0] == "string") {
        var cmd = arguments[0][0];
        if ("#+!".indexOf(cmd) > -1) return jsun.dom(arguments[0]);
    }
};

jsun.core = { };

jsun.core.member = function (val) {this.v = val;};

jsun.core.member.prototype = {
    valueOf: function () {return this.v;}
};

jsun.core.object = function () { };

jsun.core.object.prototype = {construct: function () { }, _init: true};

jsun.core.object.extend = function (prototype) {

    var _this = this;

    var obj = function () {
        var _obj = this;

        // объект родительского класса
        this.base = (function () {
            var f = function () { };
            f.prototype = _this.prototype;
            return new f();
        })();
        // конструктор родительского класса
        this.base.construct = function () {
            if (this._init) throw new Error("Base class already initialized");
            // вызов конструктора
            _this.apply(this, arguments);
            // копируем свойства потомку
            for (i in this) {
                if (!(i in _obj) && this[i] instanceof jsun.core.member)
                    _obj[i] = this[i];
            }
        };
        // копируем свойства прототипа
        for (var i in this) {
            if (this[i] instanceof jsun.core.member)
                this[i] = new jsun.core.member(this[i].v);
        }
        // вызов конструктора
        prototype.construct.apply(this, arguments);

        if (!this.base._init) throw new Error("Required initialization of the base class");
        this._init = true;
    };

    for (var i in this) {
        if (i in {"prototype": 0}) continue;
        obj[i] = this[i];
    }
    for (i in prototype) {
        if (! (typeof prototype[i] == "function"))
            prototype[i] = new jsun.core.member(prototype[i]);
    }
    for (i in this.prototype) {
        if (i in {"construct": 0}) continue;
        if (!(i in prototype) && typeof this.prototype[i] == "function") {
            (function () {
                var j = i;
                prototype[j] = function () {
                    return this.base[j].apply(this.base, arguments);
                };
            })();
        }
    }
    if (!prototype.construct)
        prototype.construct = function () {this.base.construct();}

    prototype.self = obj;
    obj.prototype = prototype;

    return obj;
};


jsun.ajax = jsun.core.object.extend( {
    req:    null,
    method: null,
    asyn:   null,
    url:    null,
    handler:null,
    headers:null,
    construct: function(p) {
        this.req.v = jsun.ajax.create_request_object();
        this.method.v = p.method || "post";
        this.asyn.v = p.asyn !== undefined ? p.asyn : true;
        this.url.v = p.url || "?";
        this.handler.v = p.handler;
        this.headers.v = {};
        this.add_header("Content-Type", "application/x-www-form-urlencoded");
    },
    send: function(param, ready) {
        var method = this.method.v,
            asyn = this.asyn.v,
            url = this.url.v,
            handler = this.handler.v;

        var req = this.req.v;
        req.open(method, url, asyn);
        for (var i in this.headers.v)
            req.setRequestHeader(i, this.headers.v[i]);

        if (asyn) {
            req.onreadystatechange = function() {
                if (ready && req.readyState == 4 && req.status == 200) handler(req);
                else if (!ready) handler(req);
            }
        } else {req.onreadystatechange = null};

        req.send(param);
        return req;
    },
    reset: function(p) {
        this.req.v.abort();
        this.method.v = p.method;
        this.asyn.v = p.asyn;
        this.url.v = p.url;
        this.handler.v = p.handler;
        this.headers.v = {};
        this.add_header("Content-Type", "application/x-www-form-urlencoded");
    },
    add_header: function(header, value) {
        this.headers.v[header] = value;
    }
});

jsun.ajax.create_request_object = function () {
    try {return new XMLHttpRequest();} catch(e){}
    try {return new ActiveXObject("Msxml2.XMLHTTP.6.0");} catch(e) {}
    try {return new ActiveXObject("Msxml2.XMLHTTP.3.0");} catch(e) {}
    try {return new ActiveXObject("Msxml2.XMLHTTP");} catch(e) {}
    try {return new ActiveXObject("Microsoft.XMLHTTP");} catch(e) {}
	throw new Error("This browser does not support XMLHttpRequest.");
};

jsun.ajax.send_request = function (p) {
    var req = new jsun.ajax(p);
    for (var i in p.headers) {
        req.add_header(i, p.headers[i]);
    }
    return req.send(p.param, p.ready);
};


jsun.eval = function (script) {
        if (window.execScript) return window.execScript(script);
        else return window.eval.call(window, script);
};

jsun.include = function(file_name) {
    jsun.run(function(req){
        try {
            if (req.status == 200) {
                jsun.eval(req.responseText);
                jsun.include.files[file_name] = true;
            } else {
                throw Error('Не удалось загрузить ' + file_name);
            }
        } catch (e) {
            jsun.dialog.warning('Ошибка', e).show();
        }
    }, jsun.ajax.send_request({method: 'GET', asyn: false, url: file_name}))
};

jsun.include.files = [];

jsun.include_once = function(file_name) {
    if (!jsun.include.files || !jsun.include.files[file_name])
        jsun.include(file_name);
};


jsun.swap = {};

jsun.run = function(fun, p) {fun(p);};


jsun.json = {};

jsun.json.load = function (func, param) {
    jsun.ajax.send_request({handler: function(req) {
        try {
            func(jsun('!' + req.responseText));
        } catch(e) {
            jsun.dialog.warning('Ошибка', req.responseText).show();
        }
    }, param: param, ready: true});
    return true;
};

jsun.json.sync_load = function (param) {
    var req = jsun.ajax.send_request({asyn: false, param: param});
    try {
        return jsun('!' + req.responseText);
    } catch(e) {
        jsun.dialog.warning('Ошибка', e).show();
        return null;
    }
};


jsun.html = {};

jsun.html.load = function (handler, param) {
    jsun.ajax.send_request({handler: function(req) {
        try {
            handler(req.responseText);
        } catch (e) {
            jsun.dialog.warning('Ошибка', e).show();
        }
    }, param: param, ready: true});
    return true;
};

jsun.html.sync_load = function (param) {
    var req = jsun.ajax.send_request({asyn: false, param: param});
    try {
        return req.responseText;
    } catch(e) {
        jsun.dialog.warning('Ошибка', e).show();
        return null;
    }
};

jsun.html.insert = function(client, html) {
    client = client || document.createElement('div');
    client.innerHTML = html;
    var scripts = client.getElementsByTagName('script');
    for (var i = 0; i < scripts.length; ++i) {
        jsun.run(new Function("", scripts[i].innerHTML));
    }
    return client;
};

//////////////////////////////////////////////////////////////
//////////////////////////PAGE////////////////////////////////
//////////////////////////////////////////////////////////////
jsun.page = jsun.core.object.extend({
    req: null,
    name: null,
    data: null,
    construct: function(id, name, req) {
        this.req.v = req;
        this.name.v = name;
        jsun.page.stack.push(this);
        jsun.page.active = this;
    },
    load: function() {

    },
    save_data: function() {
        this.data.v = jsun.page.get_data();
    }
});

jsun.page.stack = [];

jsun.page.assoc = {};

jsun.page.data = [];

jsun.page.client = document.body;

//jsun.page.load = function (param, load_data, save_data, func_before, func_after) {
//    if (save_data === undefined) save_data = true;
//    jsun.json.load(function(p) {
//        try {
//            if (typeof func_before == "function") func_before();
//            save_data && jsun.page.data.push(jsun.page.get_data());
//
//            jsun.page.client.innerHTML = "";
//            jsun.page.client.appendChild(jsun.dom.from_json(p));
//
//            jsun.page.stack.push(params);
//            load_data && jsun.page.load_data(jsun.page.data.pop());
//            jsun.page.active = params;
//            if (typeof func_after == "function") func_after();
//        } catch (e) {
//            jsun.dialog.warning('Ошибка', 'Ошибка при загрузке страницы; ' + e).show();
//        }
//    }, param);
//    return true;
//};
//
//jsun.page.back = function() {
//    jsun.page.stack.pop();
//    return jsun.page.load(jsun.page.stack.pop(), true, false);
//};
//
//jsun.page.back_if = function (param, cond) {
//    cond = cond || function() {return 1;};
//    jsun.ajax.simple_request(function(req) {
//        if (cond(req.responseText))
//            jsun.page.back();
//        else jsun.insert_html(jsun.page.client, req.responseText)
//    }, param)
//    return true;
//};
//
//jsun.page.update = function(req, load_data) {
//    if (load_data === undefined) load_data = true;
//    var page = jsun.page.stack.pop();
//    req = req || page;
//    return jsun.page.load(req, load_data);
//};
//
//jsun.page.my = function(req) {
//    jsun.page.stack.pop();
//    jsun.page.stack.push(req);
//};

jsun.page.get_data = function(p) {

    p = p || {};
    var page = p.page || jsun.page.client,
        elem = p.elem;

    var data = {}, id;

    var input = page.getElementsByTagName("input");
    for (var i = 0; i < input.length; ++i) {
        var type = input[i].getAttribute("type");
        id = input[i].getAttribute("id");

        if (["text" ,"password", "hidden", "date"].lastIndexOf(type) > -1
            && id && (!elem || elem.lastIndexOf(id) > -1))
            data[id] = input[i].value;
    }

    var select = page.getElementsByTagName("select");
    for (i = 0; i < select.length; ++i) {
        id = select[i].getAttribute("id");

        if (id && (!elem || elem.lastIndexOf(id) > -1))
            data[id] = select[i].value;
    }

    var area = page.getElementsByTagName("textarea");
    for (i = 0; i < area.length; ++i) {
        id = area[i].getAttribute("id");

        if (id && (!elem || elem.lastIndexOf(id) > -1))
            data[id] = area[i].value;
    }
    data.toString = function() {
        var str = "";
        for (var i in this) {
            if (typeof this[i] == "string" ) str += "&" + i + "=" + encodeURIComponent(data[i]);
        }
        return str;
    }
    return data;
};

jsun.page.load_data = function(data, page) {
    page = page || jsun.page.client;
    for (var i in data) {
        if (typeof data[i] == "string" )
            jsun("#" + i).value = data[i];
    }
    return true;
};

//////////////////////////////////////////////////////////////
//////////////////////////DIALOG//////////////////////////////
//////////////////////////////////////////////////////////////

jsun.dialog = jsun.core.object.extend({
    div: null,
    form: null,
    width: null,
    id: null,
    content: null,
    construct: function(param) {
        if (!param) param = { };
        if (param.width) this.width.v = param.width;
        if (param.id) this.id.v = param.id;

        this.__create(param.id, param.content, param.width, param.title);
    },
    show: function(req) {
        if (req) this.load(req);
        jsun.dialog.stack.push(this);
        jsun.dialog.active = this;
        this.form.v.style.top = (window.pageYOffset + 100) + "px";
        this.form.v.style.left = (window.screen.width / 2.5 - 100) + "px";

        this.div.v.setAttribute("class", "Dialog");
        this.div.v.focus();
        return true;
    },
    load: function(req, func_before, func_after) {
        var _this = this;
        jsun.json.load(function(p) {
            try {
                if (typeof func_before == "function") func_before();

                _this.content.v.innerHTML = "";
                _this.content.v.appendChild(jsun.dom.from_json(p));

                if (typeof func_after == "function") func_after();
            } catch (e) {
                jsun.dialog.warning('Ошибка', 'Ошибка при загрузке; ' + e).show();
            }
        }, req);
        return true;
    },
    hide: function() {
        jsun.dialog.stack.pop().div.v.setAttribute("class", "Hide Dialog");
    },
    close: function() {
        var div = jsun.dialog.stack.pop().div.v;
        div.parentNode.removeChild(div);
        return true;
    },
    close_if: function(param, update, cond) {
        cond = cond || function(u) {return u === "";};
        var _this = this;
        jsun.ajax.simple_request(function(req) {
            if (cond(req.responseText)) {
                update && jsun.page.update();
                _this.close();
            }
            else jsun.insert_html(_this.content.v, req.responseText)
        }, param)
        return true;
    },

    __create: function(id, cont, width, title) {

        ++jsun.dialog.id
        id = id || jsun.dialog.id;
        jsun.swap[id] = { };

        var _this = this;
        var head = {
                tag: "div", attr: {"class": "Head"},
                body: [
                    {tag: "div", attr: {"class" : "HeadTitle"}},
                    {tag: "div", attr: {"class" : "HeadButton"},
                        body: [ {text: "X"} ],
                        evn: {onclick: function() {return _this.close()}}}
                ]
            },
            content = {
                tag: "div", attr: {"class": "Content"}
            },
            form = {
                tag: "div", attr: {"class": "Form"},
                body: [ head, content ]
            },
            background = {
                tag: "div", attr: {"class": "Background"}
            },
            div = jsun.dom.from_json({
                tag: "div", attr: {"class": "Hide Dialog"},
                body: [ background, form ]
            });

        background = div.firstChild;
        form = div.lastChild;
        head = form.firstChild;
        content = form.lastChild;

        var head_title = head.firstChild,
            head_button = head.lastChild;

        var mouse_pos = function(e) {
                jsun.swap.MOUSE = {X:e.pageX, Y:e.pageY};
                form_move();
            },
            form_down = function() {
                window.onmousemove = mouse_pos;
                window.onmouseup = form_up;

                jsun.swap[id].DOWN = true;

            },
            form_up = function() {
                jsun.swap[id].DOWN = false;
                window.onmousemove = null;
                window.onmouseup = null;
                jsun.swap[id].POS = null;
            },
            form_move = function() {
                if (jsun.swap[id].POS) {
                    var dx = jsun.swap[id].POS.X - jsun.swap.MOUSE.X,
                        dy = jsun.swap[id].POS.Y - jsun.swap.MOUSE.Y,
                        y = form.offsetTop - dy,
                        x = form.offsetLeft - dx;
                    form.style.top = y + "px";
                    form.style.left = x + "px";
                }
                jsun.swap[id].POS = {X:jsun.swap.MOUSE.X, Y:jsun.swap.MOUSE.Y};
            };

            jsun.dom.mix(head).event({onmousedown: form_down});
            jsun.dom.mix(head).event({onmouseup: form_up});

        this.div.v = div;
        this.form.v = form;
        this.content.v = content;

        title && head_title.appendChild(jsun.dom.from_json({text: title}));
        id && div.setAttribute("id", id);

        cont && content.appendChild(cont);
        width && form.setAttribute("style", "width: " + width + "px;");

        jsun.page.client.appendChild(div);
        return div;
    }
});

jsun.dialog.id = 0;

jsun.dialog.stack = [];

jsun.dialog.warning = function(title, message, func) {
    var dlg = new jsun.dialog({title: title,
        content: jsun.dom.from_json({
            tag: 'div', body:[
                {tag: 'div', attr: {'class': "Area"}, body: [
                    {text: message}
                ]},
                {tag: "div", attr: {'class': 'ControlPanel'}, body: [
                    {tag: 'input', attr: {type: 'button', value: 'OK', style: 'width: 10em;'},
                        evn: {onclick: function(){
                                func && func();
                                jsun.dialog.active.close();
                            }}}
                ]}
            ]
        })});
    return dlg;
};

jsun.dialog.confirm = function(title, message, handler) {
    var dlg = new jsun.dialog({title: title,
        content: jsun.dom.from_json({
            tag: 'div', body:[
                {tag: 'div', attr: {'class': "Area"}, body: [
                    {text: message}
                ]},
                {tag: "div", attr: {'class': 'ControlPanel'}, body: [
                    {tag: 'input', attr: {type: 'button', value: 'Да', style: 'width: 10em;'},
                        evn: {onclick: handler}},
                    {tag: 'input', attr: {type: 'button', value: 'Отмена', style: 'width: 10em;'},
                        evn: {onclick: function(){jsun.dialog.active.close();}}}
                ]}
            ]
        })});
    return dlg;
};


jsun.form_request = jsun.core.object.extend({
    form: null,
    div: null,
    construct: function() {
        var div = jsun.dom.document.createElement("div");
        div.setAttribute("style", "display: none;");

        var form = jsun.dom.document.createElement("form");
        form.setAttribute("method", "post");

        this.form.v = form;
        this.div.v = div;

        div.appendChild(form);
        document.body.appendChild(div);
    },
    submit: function(p) {
        var form = this.form.v
        form.setAttribute("action", p.url);
        p.enctype && form.setAttribute("enctype", p.enctype);

        var e = null;
        for (var i in p.data) {
            e = jsun.dom.document.createElement("input");
            e.setAttribute("type", 'hedden');
            e.setAttribute("name", i);
            e.setAttribute("value", p.data[i]);
            form.appendChild(e);
        }
        form.submit();
    },
    remove: function() {
        this.div.v.parentNode.removeChild(this.div.v);
    }
});


jsun.frame_request = jsun.core.object.extend({
    iframe: null,
    form: null,
    div: null,
    construct: function(id) {
        id = id || jsun.utils.rnd_str(4);
        var div = jsun.dom.document.createElement("div");
        div.setAttribute("style", "display: none;");

        var iframe = jsun.dom.document.createElement("iframe");
        iframe.setAttribute("id", id);
        iframe.setAttribute("name", id);

        var form = jsun.dom.document.createElement("form");
        form.setAttribute("method", "post");
        form.setAttribute("target", id);

        this.iframe.v = iframe;
        this.form.v = form;
        this.div.v = div;

        div.appendChild(iframe);
        div.appendChild(form);

        jsun.dom.document.body.appendChild(div);
    },
    submit: function(param) {
        var form = this.form.v
        form.setAttribute("action", param.url);
        param.enctype && form.setAttribute("enctype", param.enctype);
        param.onload && (this.iframe.v.onload = param.onload);

        var e = null;
        for (var i = 0; i < param.data.length; ++i) {
            e = jsun.dom.document.createElement("input");
            e.setAttribute("type", param.data[i]['type']);
            e.setAttribute("name", param.data[i]['name']);
            e.setAttribute("value", param.data[i]['val']);
            form.appendChild(e);
        }
        form.submit();
    },
    remove: function() {
        this.div.v.parentNode.removeChild(this.div.v);
    },
    document: function() {return this.iframe.v.contentDocument;},
    window: function() {return this.iframe.v.contentWindow;}
});


jsun.post_request = function (url, params) {
    var form = jsun.dom.document.createElement("form");
    form.setAttribute("method", "post");
    form.setAttribute("action", url);
    jsun.dom.document.body.appendChild(form);
    var e = null;
    for (var i in params) {
        e = jsun.dom.document.createElement("input");
        e.setAttribute("type", "hidden");
        e.setAttribute("name", params[i][0]);
        e.setAttribute("value", params[i][1]);
        form.appendChild(e);
    }
    form.submit();
    return true;
};

jsun.page.client = document.body;

jsun.include_once("pub/jsun/dom.js");
jsun.include_once("pub/jsun/utils.js");
jsun.include_once("pub/jsun/xpath.js");


jsun.show_err = function ShowError(p) {
    var err = jsun.xpath.get("//*[@class='ErrorMessage']");
    for (var i in err.elements.v) {
        var field = err.elements.v[i].getAttribute('data-field');

        if (field && field in p.ERR)
            err.elements.v[i].innerHTML
                = '<ul><li>' + p.ERR[field] + '</li></ul>';
        else err.elements.v[i].innerHTML = '';
    }
}